package com.qingzhuge.verification.utils;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.cloudauth.model.v20180916.*;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.google.gson.Gson;
import com.qingzhuge.common.validator.ValidatorUtil;
import com.qingzhuge.exception.ValidatorException;
import com.qingzhuge.verification.dto.CloudAuthRequest;
import com.qingzhuge.verification.dto.UserAuthRequest;
import com.qingzhuge.verification.dto.UserAuthResponse;
import com.qingzhuge.verification.dto.ali.DataInfo;
import com.qingzhuge.verification.entity.SysVerification;
import com.qingzhuge.verification.service.IIdCardAuthCloudVerification;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.UUID;

/**
 * @author : zero.xiao
 * @description :
 * @date : 2018/9/29 0029 下午 16:31
 * @modified :
 * @since :
 */
@Getter
@Setter
@Slf4j
public class AliCloudVerification implements IIdCardAuthCloudVerification {
    private String biz;
    private DefaultProfile profile;

    private AliCloudVerification(String biz, DefaultProfile profile) {
        this.biz = biz;
        this.profile = profile;
    }

    public static AliCloudVerification of(SysVerification verification) {
        //创建DefaultAcsClient实例并初始化
        DefaultProfile profile = DefaultProfile.getProfile(
                //默认
                "cn-hangzhou",
                //您的Access Key ID
                verification.getAccessKeyId(),
                //您的Access Key Secret
                verification.getAccessKeySecret());
        return new AliCloudVerification(verification.getBiz(), profile);
    }

    @Override
    public UserAuthResponse doAuth(CloudAuthRequest authRequest) {
        log.debug("提交申请认证:{}", authRequest);
        ValidatorUtil.validateEntity(authRequest);
        IAcsClient client = new DefaultAcsClient(profile);
        //认证ID, 由使用方指定, 发起不同的认证任务需要更换不同的认证ID
        String ticketId = UUID.randomUUID().toString();
        //1. 服务端发起认证请求, 获取到token
        GetVerifyTokenRequest tokenRequest = new GetVerifyTokenRequest();
        tokenRequest.setBiz(biz);
        tokenRequest.setTicketId(ticketId);
        tokenRequest.setSysMethod(MethodType.POST);
        //通过binding参数传入业务已经采集的认证资料，其中人像留底照片为必要字段
        //请控制单张图片大小在 2M 内，避免拉取超时
        //Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )
        //通过binding参数传入业务已经采集的认证资料，其中姓名、身份证号为必要字段
        String binding = "{\"Name\": \"" + authRequest.getName() + "\",\"IdentificationNumber\": \"" + authRequest.getIdNumber() + "\"}";
        log.debug("传入业务采集的认证资料:{}", binding);
        tokenRequest.setBinding(binding);
        try {
            GetVerifyTokenResponse response = client.getAcsResponse(tokenRequest);
            //认证token, 表达一次认证会话
            //token默认30分钟时效，每次发起认证时都必须实时获取
            String token = response.getData().getVerifyToken().getToken();
            return new UserAuthResponse(ticketId, token);
        } catch (ClientException e) {
            log.debug("实人认证:{},{}", e.getMessage(), e.getErrMsg());
            throw new ValidatorException();
        }
        //2. 服务端将token传递给无线客户端
        //3. 无线客户端用token调起无线认证SDK
        //4. 用户按照由无线认证SDK组织的认证流程页面的指引，提交认证资料
        //5. 认证流程结束退出无线认证SDK，进入客户端回调函数
        //6. 服务端查询认证状态(客户端回调中也会携带认证状态, 但建议以服务端调接口确认的为准)
    }

    @Override
    public UserAuthResponse getAuth(UserAuthRequest authRequest) {
        log.debug("获取认证结果:{}", authRequest);
        ValidatorUtil.validateEntity(authRequest);
        UserAuthResponse userAuthResponse = null;
        if (null != authRequest) {
            GetStatusRequest statusRequest = new GetStatusRequest();
            statusRequest.setBiz(biz);
            statusRequest.setTicketId(authRequest.getTicketId());
            IAcsClient client = new DefaultAcsClient(profile);
            //-1 未认证, 0 认证中, 1 认证通过, 2 认证不通过
            Integer statusCode = -1;
            try {
                GetStatusResponse response = client.getAcsResponse(statusRequest);
                statusCode = response.getData().getStatusCode();
            } catch (ClientException e) {
                e.printStackTrace();
            }
            //7. 服务端获取认证资料
            GetMaterialsRequest materialsRequest = new GetMaterialsRequest();
            materialsRequest.setBiz(biz);
            materialsRequest.setTicketId(authRequest.getTicketId());
            //-1 未认证, 0 认证中, 1 认证通过, 2 认证不通过
            //认证通过or认证不通过
            if( 1 == statusCode || 2 == statusCode ) {
                if (1 == statusCode) {
                    userAuthResponse = new UserAuthResponse(authRequest.getType(), authRequest.getTicketId(), authRequest.getToken());
                    try {
                        GetMaterialsResponse response = client.getAcsResponse(materialsRequest);
                        DataInfo data = new DataInfo();
                        data.setName(response.getData().getName());
                        data.setIdentificationNumber(response.getData().getIdentificationNumber());
                        data.setIdCardType(response.getData().getIdCardType());
                        data.setIdCardStartDate(response.getData().getIdCardStartDate());
                        data.setIdCardExpiry(response.getData().getIdCardExpiry());
                        data.setAddress(response.getData().getAddress());
                        data.setSex(response.getData().getSex());
                        data.setEthnicGroup(response.getData().getEthnicGroup());
                        data.setStatusCode(statusCode);
                        data.setAuthFacePic(response.getData().getFacePic());
                        data.setStatus(true);
                        userAuthResponse.setStatus(true);
                        String json = new Gson().toJson(data);
                        userAuthResponse.setJson(json);
                        log.debug("实人认证通过");
                    } catch (ClientException e) {
                        userAuthResponse.setStatus(false);
                        e.printStackTrace();
                    }
                } else {
                    log.debug("实人认证未通过");
                }
            }
        }
        return userAuthResponse;
    }
}
